﻿namespace MEF_Test
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Configuration;
    using System.Linq;
    using System.Windows;

    using Bricks;
    using Bricks.Actions;
    using Bricks.StronglyTypedExports;
    using Bricks.TemplateProvider;
    using Contracts;

    using Microsoft.Practices.Prism.MefExtensions;
    using Microsoft.Practices.Prism.Regions;
    using Microsoft.Practices.Unity;

    /// <summary>
    /// The prism bootstrapper for the Mydra center application.
    /// </summary>
    /// <remarks><see cref="MydraBootstrapper"/> is based on <see cref="MefBootstrapper"/>.</remarks>
    public class MydraBootstrapper : MefBootstrapper
    {
        #region Constants and Fields

        /// <summary>
        /// A list of the lazy-instanciable data templates exported by MEF Parts.
        /// </summary>
        /// <remarks>Will be used to instanciate a <see cref="TemplateProvider"/>.</remarks>
        [ImportMany(typeof(DataTemplate))]
        private IEnumerable<Lazy<DataTemplate, IMediaHandlerTemplateExportAttribute>> _dataTemplates;

        /// <summary>
        /// A list of the lazy-instanciable IMediaHandlers exported by MEF Parts.
        /// </summary>
        [ImportMany(typeof(IMediaHandlerFactory))]
        private IEnumerable<Lazy<IMediaHandlerFactory, IDictionary<string, object>>> _mediaHandlerFactories;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the region manager.
        /// </summary>
        /// <value>The region manager.</value>       
        [Import]
        public IRegionManager RegionManager { get; set; }

        #endregion

        #region Methods

        /// <summary>
        /// Configures the <see cref="P:Microsoft.Practices.Composite.MefExtensions.MefBootstrapper.AggregateCatalog"/> used by MEF.
        /// </summary>
        /// <returns>
        /// An <see cref="P:Microsoft.Practices.Composite.MefExtensions.MefBootstrapper.AggregateCatalog"/> to be used by the bootstrapper.
        /// </returns>
        /// <remarks>
        /// The base implementation returns a new AggregateCatalog.
        /// </remarks>
        protected override AggregateCatalog CreateAggregateCatalog()
        {
            var aggregateCatalog = base.CreateAggregateCatalog();

            // Read the mapping information from the config file.
            var openExeConfiguration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
            var section = (ModulesSettingsSection)openExeConfiguration.GetSection("ModulesSettingsSection");
            //FIXME  IF CONFIG DOES NOT EXIST : CREATE MEANINGFULL DEFAULT VALUES  !!!!! VERY URGENT !

             //// type="MEF_Test.Contracts.IVideoRenderer, MEF_Test.Contracts" mapTo="MEF_Test.VideoRenderer.LocalVideoRenderer.LocalVideoRenderer, MEF-Test.VideoRenderer.LocalVideoRenderer" name="MydraVideoOpenActionContextProviderFactory"
             //section.ContractToTypeMappings.AddMapping("MEF_Test.Contracts.IVideoRenderer", "MEF_Test.VideoRenderer.LocalVideoRenderer.LocalVideoRenderer");
             //section.ContractToTypeMappings.AddMapping("MEF_Test.Contracts.ISettingsManager", "MEF_Test.SettingsManager.MydraSettingsManager");
             //section.CurrentConfiguration.Save();

            var contractToTypeMappings = section.ContractToTypeMappings.GetMappingsDictionary();

            var dirCatalog = new MappableDirectoryCatalog(@".\Plugins", contractToTypeMappings);            
            aggregateCatalog.Catalogs.Add(dirCatalog);
            return aggregateCatalog;
        }

        /// <summary>
        /// Creates the shell or main window of the application.
        /// </summary>
        /// <returns>
        /// The shell of the application.
        /// </returns>
        /// <remarks>
        /// If the returned instance is a <see cref="T:System.Windows.DependencyObject"/>, the
        ///             <see cref="T:Microsoft.Practices.Composite.Modularity.Bootstrapper"/> will attach the default <seealso cref="T:Microsoft.Practices.Composite.Regions.IRegionManager"/> of
        ///             the application in its <see cref="F:Microsoft.Practices.Composite.Presentation.Regions.RegionManager.RegionManagerProperty"/> attached property
        ///             in order to be able to add regions by using the <seealso cref="F:Microsoft.Practices.Composite.Presentation.Regions.RegionManager.RegionNameProperty"/>
        ///             attached property from XAML.
        /// </remarks>
        protected override DependencyObject CreateShell()
        {
            IoC.SetContainer(new UnityContainer());

            InitializeIoC();            
            // FIXME : Use a DI'd factory to instanciate the right view. (monoscreen-multiscreen-remotescreen-whatever)
            var mainWindow = new SingleMonitorShell();
            mainWindow.Show();

            return mainWindow;
        }

        /// <summary>
        /// The initialize the ioc.
        /// </summary>
        private void InitializeIoC()
        {
            var container = this.Container;

            IoC.Current.RegisterInstance(container);

            // discover with MEF the types we want to use, and inject them !
            IoC.Current.RegisterInstance<IActionsManager>(new ActionsManager());
            container.ComposeParts(this);

            // convert a list of all the mediahandlers discovered within exported parts to a dictionary. 
            // Note : if two different parts export a mediaHandler for the same ContentType, there's going to be a conflict.
            // Todo : add a configuration mechanism to define which media handler should take precedence over the others.
            // For now, we're just going to assume nobody will install a part that exports a mediaHandler for a content type which is already taken care of by an other mediahandler.
            Dictionary<string, IMediaHandlerFactory> mediaHandlersDictionary =
                _mediaHandlerFactories.ToDictionary(o => (string)o.Metadata["ContentType"], o => o.Value);

            // Registers a Template Provider with a list of data templates discovered in exported parts.
            IoC.Current.RegisterInstance(new TemplateProvider(_dataTemplates));

            // Registers a media handler factory with a list of all the available media handlers discovered in the exported parts.
            Dictionary<string, string> extensionToContentTypeMappings =
                _mediaHandlerFactories.Where(o => o.Metadata.ContainsKey("Extension")).ToDictionary(o => (string)o.Metadata["Extension"], o => (string)o.Metadata["ContentType"]);
            IoC.Current.RegisterInstance<IMediaHandlerFactoryProvider>(
                new MediaHandlerFactoryProvider(mediaHandlersDictionary, extensionToContentTypeMappings));

            IoC.Current.RegisterInstance<IBrowserDetailViewModelFactory>(new BrowserDetailViewModelFactory());
        }

        #endregion
    }
}
